package com.huynhchihieu.controller;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.huynhchihieu.customrespone.CustomFamilyRespone;
import com.huynhchihieu.customrespone.CustomJobRespones;
import com.huynhchihieu.customrespone.CustomUserResponse;
import com.huynhchihieu.domain.Book;
import com.huynhchihieu.domain.CustomBookResponse;
import com.huynhchihieu.domain.CustomGenericResponse;
import com.huynhchihieu.domain.Family;
import com.huynhchihieu.domain.Job;
import com.huynhchihieu.domain.User;
import com.huynhchihieu.exception.CustomGenericException;
import com.huynhchihieu.repository.BookRepository;
import com.huynhchihieu.repository.FamilyRepository;
import com.huynhchihieu.repository.JobRepository;
import com.huynhchihieu.repository.UserRepository;
import com.huynhchihieu.service.BookService;
import com.huynhchihieu.service.FamilyService;
import com.huynhchihieu.service.JobService;

@Controller
@EnableJpaRepositories
public class RelationShipExampleController {

	Logger log = Logger.getLogger(RelationShipExampleController.class);
	
	@Autowired ServletContext servletContext;
	
	@Autowired(required = true)
	@Qualifier(value = "jobServiceImpl")
	JobService jobService;

	@Autowired
	FamilyService familyService;

	/*
	 * Qualifier =>In the simplest case, this can be a plain descriptive value
	 * For a fallback match, the bean name is considered as a default qualifier
	 * value
	 * 
	 * @Autowired is fundamentally about type-driven injection with optional
	 * semantic qualifiers
	 */
	// @Autowired
	// @Qualifier(value = "jobServiceImplTemp")
	// GenericService<Job> jobServiceGeneric;
	//
	// @Autowired
	// @Qualifier(value = "useTestServiceImpl")
	// GenericService<User> useTestServiceImpl;

	@Autowired(required = true)
	UserRepository userRepository;

	@Autowired(required = true)
	JobRepository jobRepository;

	@Autowired
	FamilyRepository familyRepository;

	@Autowired
	BookRepository bookRepository;

	@Autowired
	BookService bookService;

	enum EVENT_TYPE {
		DELETE, UPDATE, CREATE, CLEARCACHE, SEARCH, DEFAULT
	}

	@RequestMapping("/job")
	public String person(Model model) {
		Job job = new Job();
		model.addAttribute("job", job);
		return "job";
	}

	@RequestMapping(value = "/addJob", method = RequestMethod.POST)
	public String addPersion(@ModelAttribute("job") Job job, ModelMap model) {
		try {
			// jobServiceGeneric.create(job);
			jobService.addJob(job);
			model.addAttribute("message", "true");
			log.debug("add sucessful!");
		} catch (Exception e) {
			e.printStackTrace();
			log.debug(e.getMessage());
			model.addAttribute("message", "false");
		}
		return "forward:/job";

	}

	@RequestMapping(value = "/getAll", method = RequestMethod.GET)
	public @ResponseBody CustomUserResponse getAll(HttpServletRequest request) {
		log.debug("Received request to get all users");

		// Retrieve all users from the service
		List<User> users = (List<User>) userRepository.findAll();

		// Initialize our custom user response wrapper
		CustomUserResponse responses = new CustomUserResponse();
		int rows = Integer.parseInt(request.getParameter("rows"));
		int page = Integer.parseInt(request.getParameter("page"));
		// String sidx = request.getParameter("sidx");
		// String sord = request.getParameter("sord");
		responses.setRows(users);
		int count = users.size();
		int total = count % rows == 0 ? (int) Math.ceil(count / rows) : (int) Math.ceil(count / rows) + 1;
		responses.setTotal(String.valueOf(total));
		responses.setRecords(String.valueOf(count));
		responses.setPage(String.valueOf(page));
		return responses;
	}

	@RequestMapping(value = "/getAllJobs", method = RequestMethod.GET)
	public @ResponseBody CustomJobRespones getAllJob(HttpServletRequest request) {
		CustomJobRespones respones = new CustomJobRespones();
		List<Job> jobs = (List<Job>) jobRepository.findAll();
		int rows = Integer.parseInt(request.getParameter("rows"));
		int page = Integer.parseInt(request.getParameter("page"));
		// String sidx = request.getParameter("sidx");
		// String sord = request.getParameter("sord");
		respones.setRows(jobs);
		int count = jobs.size();
		int total = count % rows == 0 ? (int) Math.ceil(count / rows) : (int) Math.ceil(count / rows) + 1;
		respones.setTotal(String.valueOf(total));
		respones.setRecords(String.valueOf(count));
		respones.setPage(String.valueOf(page));
		return respones;
	}

	@RequestMapping(value = "/getAllFamily", method = RequestMethod.GET)
	public @ResponseBody CustomFamilyRespone getAllFamily(HttpServletRequest request) {
		CustomFamilyRespone respones = new CustomFamilyRespone();
		List<Family> jobs = (List<Family>) familyService.getAllFamilies();
		int rows = Integer.parseInt(request.getParameter("rows"));
		int page = Integer.parseInt(request.getParameter("page"));
		// String sidx = request.getParameter("sidx");
		// String sord = request.getParameter("sord");
		respones.setRows(jobs);
		int count = jobs.size();
		int total = count % rows == 0 ? (int) Math.ceil(count / rows) : (int) Math.ceil(count / rows) + 1;
		respones.setTotal(String.valueOf(total));
		respones.setRecords(String.valueOf(count));
		respones.setPage(String.valueOf(page));
		return respones;
	}

	@RequestMapping(value = "/books", method = RequestMethod.GET)
	public void books(Model model
			//, @ModelAttribute Book book
			, @RequestParam(value = Constant.EVENT_TYPE, required=false) String eventType
			, @RequestParam(value= Constant.IDRECORD, required=false) String idRecord
			, @RequestParam(value= Constant.BOOKNAME, required=false) String  bookName) {
/*		final String DELETE = "DELETE";
		final String UPDATE = "UPDATE";
		final String CREATE = "CREATE";
		final String  CLEARCACHE = "CLEARCACHE";
		final String SEARCH = "SEARCH";
		final String DEFAULT = "DEFAULT";
		// add ModelAtrribute
		model.addAttribute("modelBook", new Book());
		EVENT_TYPE enumType = null;
		//String eventType = request.getParameter(Constant.EVENT_TYPE);
		List<Book> books = null;
		if (Constant.DELETE.equals(eventType)) {
			enumType = EVENT_TYPE.valueOf(DELETE);
		} else if (Constant.UPDATE.equals(eventType)) {
			enumType = EVENT_TYPE.valueOf(UPDATE);
		} else if (Constant.CREATE.equals(eventType)) {
			enumType = EVENT_TYPE.valueOf(CREATE);
		} else if (Constant.CLEARCACHE.equals(eventType)) {
			enumType = EVENT_TYPE.valueOf(CLEARCACHE);
		} else if (Constant.SEARCH.equals(eventType)) {
			enumType = EVENT_TYPE.valueOf(SEARCH);
		} else {
			enumType = EVENT_TYPE.valueOf(DEFAULT);
		}
		switch (enumType) {
		case DELETE:
			//int id = Integer.valueOf(request.getParameter("idRecord"));
			Book bookDelete = bookService.findById(Integer.valueOf(idRecord));
			bookService.delete(bookDelete);
			books = bookService.getAllBooks();
			break;
		case CREATE:
			bookService.addBook(book);
			books = bookService.getAllBooks();
			break;
		case UPDATE:
			bookService.updateBook(book);
			books = bookService.getAllBooks();
			break;
		case CLEARCACHE:
			bookService.clearCached();
			books = bookService.getAllBooks();
			break;
		case SEARCH:
			//String bookName = request.getParameter("bookName");
			if (!bookName.isEmpty()) {
				books = new ArrayList<Book>();
				Book bookSearch = bookService.finByName(bookName);
				books.add(bookSearch);
			} else {
				books = bookService.getAllBooks();
			}
			break;
		default:
			books = bookService.getAllBooks();
			break;
		} // books =
		bookService.getAllBooks();
		model.addAttribute("books", books);*/
		//return "books";

	}
	
	@RequestMapping(value="/bookjqgrid")
	public String bookJqgrid(){
		return "bookjqgrid";
	}

	@ExceptionHandler(CustomGenericException.class)
	public ModelAndView handleCustomException(CustomGenericException ex) {

		return new ModelAndView("hello");

	}
	
	@RequestMapping("/clearCached")
	public String clearCache() {
		bookService.clearCached();
		return "redirect:books";
	}
	
	@RequestMapping(value="/editBookJqgrid", method=RequestMethod.POST)
	public @ResponseBody CustomGenericResponse editBook(
			@RequestParam("bookAuthor") String bookAuthor,
			@RequestParam("numpages") String numpages,
			@RequestParam("bookId") String bookId,
			@RequestParam("bookName") String bookName,
			@RequestParam("category") String category,
			@RequestParam("price") String price){
		CustomGenericResponse  customGenericResponse = new CustomGenericResponse();
		// TODO
		Book book = new Book();
		book.setBookId(bookId==""?0:Integer.parseInt(bookId));
		book.setBookAuthor(bookAuthor);
		book.setBookName(bookName);
		book.setCategory(category);
		book.setNumpages(numpages==""?0:Integer.parseInt(numpages));
		book.setPrice(price==""?0:Float.parseFloat(price));
		bookService.updateBook(book);
		customGenericResponse.setSuccess(true);
		return  customGenericResponse;
	}
	
	/**
	 * If you use the @RequestBody annotation then I believe Spring MVC is expecting to map the entire body of the POST request to an Object.
	 *  I'm guessing your body is not simply a String, but some full JSON object.
	 * @param books
	 * @return
	 */
	@RequestMapping(value="/editBooksJqgrid", method=RequestMethod.POST)
	public  @ResponseBody CustomGenericResponse editBooks(@RequestBody List<Book> books){
		CustomGenericResponse  customGenericResponse = new CustomGenericResponse();
		for(Book book : books){
			bookService.updateBook(book);
		}
		customGenericResponse.setSuccess(true);
		return  customGenericResponse;
	}
	public void methodonserver1(){
		
		
	}

	public void methodonlocal1(){
		
		
	}
	
	@RequestMapping(value="/deleteBookJqgrid", method=RequestMethod.POST)
	public @ResponseBody CustomGenericResponse deleteBookJqgrid(@RequestParam("id") String bookId){
		CustomGenericResponse  customGenericResponse = new CustomGenericResponse();
		// TODO
		Book book = bookService.findById(Integer.parseInt(bookId));
		bookService.delete(book);
		customGenericResponse.setSuccess(true);
		return  customGenericResponse;
	}
	
	@RequestMapping(value="/updateBook", method= RequestMethod.POST)
	public @ResponseBody List<Book> updateBook(
			@RequestParam(value="filename", required=false) MultipartFile file,
			@RequestParam(value="idChange", required=false) String id,
			@RequestParam(value="nameChange", required=false) String name,
			@RequestParam(value="authorChange", required=false) String author,
			@RequestParam(value="categoryChange", required=false) String category,
			@RequestParam(value="numpagesChange", required=false) String numpages,
			@RequestParam(value="priceChange", required=false) String price) throws IOException {
		// upload images
		String fileName = null;
		if (!file.isEmpty()) {
			BufferedOutputStream stream = null;
            try {
                byte[] bytes = file.getBytes();
 
                String webappRoot = servletContext.getRealPath("/");
                String relativeFolder = File.separator + "resources" + File.separator
                                         + "images" + File.separator;
                String filename = webappRoot + relativeFolder;
                // Create the folder on server to store file
                File dir = new File(filename);
                if (!dir.exists())
                    dir.mkdirs();
 
               
                Date date = new Date();
                long times = date.getTime();
                // filename = datetime + original name of file
                File serverFile = new File(dir.getAbsolutePath()
                        + File.separator + times + file.getOriginalFilename());
                // get file name 
                 fileName = serverFile.getName();
                 stream = new BufferedOutputStream(
                        new FileOutputStream(serverFile));
                stream.write(bytes);
            } catch (Exception e) {
                e.printStackTrace();
            } finally{
					stream.close();
            }
        }
		// update book if it's exist or create book if otherwise
		Book book = new Book();
		book.setBookId(Integer.parseInt(id));
		book.setBookName(name);
		book.setBookAuthor(author);
		book.setCategory(category);
		book.setNumpages(Integer.parseInt(numpages));
		book.setPrice(Float.parseFloat(price));
		book.setImages(fileName);
		bookService.updateBook(book);
		// get books after update book
		List<Book> books = bookService.getAllBooks();
		return books;
	}
	
	@RequestMapping(value="/getAllBooks", method=RequestMethod.POST)
	public @ResponseBody List<Book> getAllBooks(){
		return bookService.getAllBooks();
	}
	
	@RequestMapping(value="/mangebooks", method= RequestMethod.POST)
	public @ResponseBody CustomBookResponse getAllbooksJqgrid(){
		CustomBookResponse customBookResponse = new CustomBookResponse();
		 customBookResponse.setPage(1);
		 customBookResponse.setRecords(3);
		 customBookResponse.setTotal(5);
		 customBookResponse.setRows(bookService.getAllBooks());
		 return customBookResponse;
	}

	@RequestMapping(value = "/deleteRecord", method = RequestMethod.POST)
	public @ResponseBody List<Book> deleteRecord(@RequestBody Map json) {
		String id = (String) json.get("id");
		Book book = bookService.findById(Integer.parseInt(id));
		bookService.delete(book);
		return bookService.getAllBooks();
	}
	
	@RequestMapping(value="/findBooks", method= RequestMethod.GET)
	public @ResponseBody List<Book> searchBook(@RequestParam("bookName") String bookName){
		
		return bookService.finByNames(bookName);
	}
	
	@RequestMapping(value = "/getTags", method = RequestMethod.GET)
	public @ResponseBody
	List<Book> getTags(@RequestParam("term") String query) {
 
		return simulateSearchResult(query);
 
	}
	
	private List<Book> simulateSearchResult(String query) {
		query = query.toLowerCase();
		String bookName = null;
		List<Book> result = new ArrayList<Book>();
		List<Book> books = bookService.getAllBooks();
		// iterate a list and filter by tagName
		for (Book book : books) {
			bookName = book.getBookName().toLowerCase();
			if(bookName.startsWith(query)){
				result.add(book);
			}
		}
		return result;
	}
}
